home *** CD-ROM | disk | FTP | other *** search
- /*
- File: IconButton.c
-
- Contains: CDEF implementing Icon Button
-
- Written by: Arno Gourdol
-
- Copyright: © 1993-1996 by Apple Computer, Inc., all rights reserved.
-
- */
-
-
- /*
- How to use...
-
- Create a control with the following ID:
- 64: 32x32 icon
- 65: 16x16 icon
- 66: 12x12 icon
-
- The value of the control is the ID of the icon family to
- use to display (icl8, icl4, ICON...).
- */
-
- #include <Controls.h>
- #include <Windows.h>
- #include <QDOffscreen.h>
- #include <LowMem.h>
- #include <Icons.h>
-
-
- // Variants
- enum
- {
- kLargeIconVariant = 0x00, // Use 32x32 icon
- kSmallIconVariant = 0x01, // Use 16x16 icon
- kMiniIconVariant = 0x02 // Use 12x12 icon
- };
-
-
- struct DrawControlInfo
- {
- Rect controlBounds; // Rectangle enclosing the button
- Boolean hilited; // True if button is pushed
- Boolean active; // True if button is not dimmed
- SInt16 iconFamilyID; // Icon family ID or -1
- UInt16 variant;
- };
- typedef struct DrawControlInfo DrawControlInfo;
-
- struct PortState
- {
- // Port we switched from
- GrafPtr savedPort;
-
- // Saved state of the WMgrCPort
- RgnHandle savedClip;
- Point savedOrigin;
- RGBColor savedFgColor;
- RGBColor savedBgColor;
- PenState savedPen;
- SInt16 savedPenVis;
- SInt16 savedTxMode;
-
- };
- typedef struct PortState PortState;
-
-
- pascal long main(UInt16 variant, ControlHandle theControl, SInt16 message, UInt32 param);
-
- Boolean UseGrayUI(UInt16 depth, UInt16 deviceFlags);
- void SetForeGray(UInt16 value);
- UInt16 GetIconSize(UInt16 variant);
- Boolean GetIconRect(const Rect& controlBounds, UInt16 variant, Rect* iconRect);
-
- void DoDrawControl(ControlHandle theControl, UInt16 variant);
- long DoTestControl(ControlHandle theControl, Point hit);
- void DoCalcRegion(ControlHandle theControl, RgnHandle controlRegion);
-
- void SetWindowManagerPort(PortState *state);
- void RestoreSavedPort(PortState *state);
- Boolean AreWeOffscreen(void);
-
-
- // WARNING: Some compilers require the main entry point to be
- // the first routine in the source file.
- pascal long main(UInt16 variant, ControlHandle theControl, SInt16 message, UInt32 param)
- {
- long result = 0;
-
- if (message > 2)
- message -= 7;
-
- switch (message)
- {
- // Handle draw message
- case drawCntl:
- DoDrawControl(theControl, variant);
- break;
-
- // Handle hit-test message
- case testCntl:
- result = DoTestControl(theControl, *(Point *)¶m);
- break;
-
- // Handle 24-bit mode calc regions call
- case calcCRgns:
- // 24-bit dirty version
- param &= 0x00FFFFFF; // Clear the high byte
- DoCalcRegion(theControl, (RgnHandle)param);
- param &= 0x7FFFFFFF; // Clear high bit
- break;
-
- case calcCntlRgn-7:
- case calcThumbRgn-7:
- // 32-bit clean
- DoCalcRegion(theControl, (RgnHandle)param);
- break;
- }
-
- return result;
- }
-
-
-
- // --------------------------------------------------------------------
- // AreWeOffscreen
- // --------------------------------------------------------------------
- //
- // Compares base address of the current port to screen base to
- // determine if we're drawing on or offscreen.
- //
-
- Boolean AreWeOffscreen(void)
- {
- GrafPtr savedPort;
- Ptr baseAddr;
-
- GetPort(&savedPort);
-
- // If we're color, then we get base address
- // from pixmap....
- if (((CGrafPtr)savedPort)->portVersion & 0xC000)
- baseAddr = (**((CGrafPtr)savedPort)->portPixMap).baseAddr;
- else
- baseAddr = savedPort->portBits.baseAddr;
-
- return baseAddr != LMGetScrnBase();
- }
-
-
-
- // --------------------------------------------------------------------
- // UseGrayUI
- // --------------------------------------------------------------------
- //
- // Returns true if color environment is sufficient to use shades of
- // grey.
- //
-
- Boolean UseGrayUI(UInt16 depth, UInt16 deviceFlags)
- {
- // If bith depth is 256 colors or more,
- // or if 4 bit depth gray scale the use gray UI
- return (depth >= 8) || ((depth == 4) && !(deviceFlags & (1L << gdDevType)));
- }
-
-
-
- // --------------------------------------------------------------------
- // SetForeGray
- // --------------------------------------------------------------------
- //
- // Set the fore color to a shade of grey.
- //
-
- void SetForeGray(UInt16 value)
- {
- RGBColor color;
-
- color.red = value;
- color.green = value;
- color.blue = value;
-
- RGBForeColor(&color);
- }
-
-
-
- // --------------------------------------------------------------------
- // GetIconSize
- // --------------------------------------------------------------------
- //
- // Returns the icon size in pixel, based on the variant.
- //
-
- UInt16 GetIconSize(UInt16 variant)
- {
- short result;
-
- switch(variant & 0x03)
- {
- case kSmallIconVariant:
- result = 16;
- break;
-
- case kMiniIconVariant:
- result = 12;
- break;
-
- default:
- result = 32; // 0 or other, 32 pixel wide icon
- }
- return result;
- }
-
-
-
- // --------------------------------------------------------------------
- // GetIconRect
- // --------------------------------------------------------------------
- //
- // Returns the rect in which to display the icon based on the variant
- // and control rect.
- // Returns true if the icon rectangle is not empty
- //
-
- Boolean GetIconRect(const Rect& controlBounds, UInt16 variant, Rect* iconRect)
- {
- Boolean result;
-
- UInt16 iconSize = GetIconSize(variant);
-
- UInt16 controlWidth = controlBounds.right - controlBounds.left;
- UInt16 controlHeight = controlBounds.bottom - controlBounds.top;
-
-
- if (controlWidth < iconSize || controlHeight < iconSize)
- {
- // The control is too small to display the icon
- // Return an empty rectangle
- iconRect->top = 0;
- iconRect->left = 0;
- iconRect->right = 0;
- iconRect->bottom = 0;
-
- result = false;
- }
- else
- {
- SInt16 temp;
- *iconRect = controlBounds;
-
- // Center the iconRect inside the controlRect, pinning it if necessary
- temp = iconRect->top + ((controlHeight - iconSize + 1) >> 1);
- if (temp > iconRect->top)
- iconRect->top = temp;
-
- temp = iconRect->left + ((controlWidth - iconSize + 1) >> 1);
- if (temp > iconRect->left)
- iconRect->left = temp;
-
- temp = iconRect->top + iconSize;
- if (temp < iconRect->bottom)
- iconRect->bottom = temp;
-
- temp = iconRect->left + iconSize;
- if (temp < iconRect->right)
- iconRect->right = temp;
-
- result = true;
- }
- return result;
- }
-
-
-
- // --------------------------------------------------------------------
- // DrawControlProc
- // --------------------------------------------------------------------
- //
- // Callback for device loop to draw the control.
- //
-
- static pascal void DrawControlProc(UInt16 depth, UInt16 deviceFlags,
- GDHandle targetDevice, DrawControlInfo* info)
- {
- #pragma unused (targetDevice)
-
- if (!UseGrayUI(depth, deviceFlags))
- {
- // Draw in black and white
- Rect frameRect = info->controlBounds;
-
- if(info->hilited)
- PaintRect(&frameRect);
- else
- EraseRect(&frameRect);
-
- FrameRect(&frameRect);
- }
- else
- {
- // Draw using shades of grey
- UInt16 fillGray;
-
- UInt16 frameHiliteGray;
- UInt16 frameShadowGray;
-
- UInt16 hiliteGray;
- UInt16 shadowGray;
- UInt16 cornerGray;
-
- UInt16 topLeftCornerGray;
- UInt16 botRightCornerGray;
- UInt16 hilite2Gray;
- UInt16 shadow2Gray;
-
- Rect frameRect = info->controlBounds;
-
- //
- // Save the background and foreground colors
- //
- RGBColor oldForeColor;
- RGBColor oldBackColor;
-
- GetForeColor(&oldForeColor);
- GetBackColor(&oldBackColor);
-
- // What is the smallest side of the frame
- // If one of the side is larger than 20, it's a big button
- Boolean isBigButton = (frameRect.right - frameRect.left > 20) ||
- (frameRect.bottom - frameRect.top > 20);
-
- //
- // Determine the colors
- //
-
- if (!info->active)
- {
- // Dimmed button
- frameHiliteGray = 0x7777;
- frameShadowGray = 0x7777;
- fillGray = 0xDDDD;
- hiliteGray = 0xEEEE;
- cornerGray = 0xCCCC;
- shadowGray = 0xAAAA;
- }
- else if (info->hilited)
- {
- // Selected (pushed) button
- frameHiliteGray = 0x2222;
- frameShadowGray = 0x6666;
- fillGray = 0x8888;
- hiliteGray = 0x5555;
- cornerGray = 0x7777;
-
- if(isBigButton)
- {
- shadowGray = 0x4444;
- shadow2Gray = 0x5555;
- hilite2Gray = 0x7777;
- topLeftCornerGray = 0x8888;
- botRightCornerGray = 0x2222;
- }
- else
- {
- shadowGray = 0xAAAA;
- }
- }
- else
- {
- // Normal button
- frameHiliteGray = 0x6666;
- frameShadowGray = 0x3333;
- fillGray = 0xCCCC;
- shadowGray = 0x9999;
- cornerGray = 0xCCCC;
-
- if(isBigButton)
- {
- botRightCornerGray = 0x8888;
- hiliteGray = 0x2222;
- hilite2Gray = 0xFFFF;
- shadow2Gray = 0x5555;
- topLeftCornerGray = 0xFFFF;
- }
- else
- hiliteGray = 0xFFFF;
- }
-
-
- //
- // Draw the button
- //
- {
- --frameRect.right;
- --frameRect.bottom;
- frameRect.left++;
- frameRect.top++;
-
- // Draw the inside of the rect
- SetForeGray(fillGray);
- PaintRect(&frameRect);
-
- // Draw the inside top left hilite thingie
- SetForeGray(hiliteGray);
- MoveTo(frameRect.left, frameRect.bottom - 1);
- LineTo(frameRect.left, frameRect.top); // Left side
- LineTo(frameRect.right - 1, frameRect.top); // Top side
-
-
- // Draw the inside bottom right shadow thingie
- SetForeGray(shadowGray);
- MoveTo(frameRect.right - 1, frameRect.top);
- LineTo(frameRect.right - 1, frameRect.bottom - 1); // Right side
- LineTo(frameRect.left + 1, frameRect.bottom - 1); // Bottom side
-
- if (isBigButton)
- {
- // Draw the more inside top left hilite thingie
- InsetRect(&frameRect, 1 , 1);
- MoveTo(frameRect.left, frameRect.bottom - 1);
- SetForeGray(hilite2Gray);
- LineTo(frameRect.left, frameRect.top ); // Left inside side
- LineTo(frameRect.right - 1, frameRect.top); // Top inside side
-
- // Draw the more inside bottom right shadow thingie
- SetForeGray(shadow2Gray);
- LineTo(frameRect.right - 1, frameRect.bottom - 1); // Right inside
- LineTo(frameRect.left + 1, frameRect.bottom - 1); // Bottom inside
- InsetRect(&frameRect, -1, -1);
- }
-
- // Draw the corners
- if (isBigButton)
- {
- SetForeGray(cornerGray);
- MoveTo(frameRect.right -1, frameRect.top);
- Line(-1, 1);
- MoveTo(frameRect.left, frameRect.bottom -1);
- Line(1, -1);
-
- SetForeGray(topLeftCornerGray);
- MoveTo(frameRect.left, frameRect.top);
- Line(0,0);
-
- SetForeGray(botRightCornerGray);
- MoveTo(frameRect.right -1, frameRect.bottom -1);
- Line(0,0);
-
- SetForeGray(shadowGray);
- MoveTo(frameRect.right - 2, frameRect.bottom - 2);
- Line(0,0);
-
- if(info->hilited)
- {
- SetForeGray(hiliteGray);
- MoveTo(frameRect.left + 1, frameRect.top + 1);
- Line(0,0);
- }
- }
- else
- {
- SetForeGray(cornerGray);
- MoveTo(frameRect.right -1, frameRect.top);
- Line(0,0);
- MoveTo(frameRect.left, frameRect.bottom -1);
- Line(0, 0);
- }
-
- --frameRect.left;
- --frameRect.top;
-
- {
- // Draw the frame
- SetForeGray(frameHiliteGray);
- MoveTo(frameRect.left, frameRect.bottom);
- LineTo(frameRect.left, frameRect.top); // Left side
- LineTo(frameRect.right, frameRect.top); // Top side
-
-
- // Draw the inside bottom right shadow thingie
- SetForeGray(frameShadowGray);
- MoveTo(frameRect.right, frameRect.top);
- LineTo(frameRect.right, frameRect.bottom); // Right side
- LineTo(frameRect.left, frameRect.bottom); // Bottom side
- }
- }
- //
- // Restore color environment
- //
- RGBForeColor(&oldForeColor);
- RGBBackColor(&oldBackColor);
- }
-
-
- //
- // Draw the icon
- //
- if (info->iconFamilyID != -1)
- {
- Rect iconRect;
-
- if (GetIconRect(info->controlBounds, info->variant, &iconRect))
- {
- // Set back to B&W before drawing icons
- ForeColor(blackColor);
- BackColor(whiteColor);
-
- {
- IconTransformType iconTransform = kTransformNone;
-
- if (!info->active)
- iconTransform = kTransformDisabled;
- else if (info->hilited)
- iconTransform = kTransformSelected;
-
- PlotIconID(&iconRect, kAlignAbsoluteCenter,
- iconTransform, info->iconFamilyID);
- }
- }
- }
-
- }
-
-
-
- // --------------------------------------------------------------------
- // DoDrawControl
- // --------------------------------------------------------------------
- //
- // CDEF entry point responsible for drawing the control.
- //
-
- void DoDrawControl(ControlHandle theControl, UInt16 variant)
- {
- DrawControlInfo drawControlInfo;
- Rect contrlRect;
- short hilite;
- GrafPtr savedPort;
- #define kFakeDeviceFlags 0xA801
-
- // Draw iff both the control and its parent window are visible
- if (!(**theControl).contrlVis || !((WindowPeek)((**theControl).contrlOwner))->visible )
- return; // Control is not visible. Don't draw anything
-
- contrlRect = (**theControl).contrlRect;
- hilite = (**theControl).contrlHilite;
- drawControlInfo.controlBounds = contrlRect;
- drawControlInfo.iconFamilyID = GetControlValue(theControl);
- drawControlInfo.variant = variant;
- drawControlInfo.hilited = (hilite > 0) && (hilite < 254);
- drawControlInfo.active = (hilite != 255);
-
- GetPort(&savedPort);
-
- // Use deviceloop iff we're on a color qd machine, if we're not offscreen
- // and if we're not in the middle of a picture definition
- if ((LMGetROM85()<=0x3FFF) && !AreWeOffscreen() && !(savedPort->picSave) )
- {
- PortState portState;
- SetWindowManagerPort(&portState);
- {
- RgnHandle contrlRgn = NewRgn();
- RectRgn(contrlRgn, &contrlRect);
- DeviceLoop(contrlRgn, (DeviceLoopDrawingProcPtr)DrawControlProc,
- (UInt32)&drawControlInfo, (DeviceLoopFlags)0);
- DisposeRgn(contrlRgn);
- }
- RestoreSavedPort(&portState);
- }
- else
- {
- GWorldPtr curWorld;
- GDHandle curGD;
-
- // Get current gworld so we can pass its device's depth to
- // our drawing proc
- GetGWorld(&curWorld, &curGD);
- DrawControlProc((**(**curGD).gdPMap).pixelSize,
- kFakeDeviceFlags, NULL, &drawControlInfo);
- }
- }
-
-
-
- // --------------------------------------------------------------------
- // DoTestControl
- // --------------------------------------------------------------------
- //
- // CDEF entry point responsible for hit-testing the control.
- //
-
- long DoTestControl(ControlHandle theControl, Point hit)
- {
- if((**theControl).contrlHilite == 255)
- {
- return 0; // If dimmed, nothing can be hit
- }
- else
- {
- Rect hitRect = (**theControl).contrlRect;
- if (PtInRect(hit, &hitRect))
- return inButton;
- else
- return 0;
- }
-
- }
-
-
-
- // --------------------------------------------------------------------
- // DoCalcRegion
- // --------------------------------------------------------------------
- //
- // CDEF entry point responsible for calculating the regions of
- // the control.
- //
-
- void DoCalcRegion(ControlHandle theControl, RgnHandle controlRegion)
- {
- Rect contrlRect = (**theControl).contrlRect;
- RectRgn(controlRegion, &contrlRect);
- }
-
-
-
- // --------------------------------------------------------------------
- // SetWindowManagerPort
- // --------------------------------------------------------------------
- //
- // Set the drawing environment to be the Window Manager.
- // Used if color is available, but the grafport in which the control
- // is draw is B&W.
- //
-
- void SetWindowManagerPort(PortState *state)
- {
- GrafPtr windowManagerPort; // WMgrCPort
- Point origin;
-
- GetPort(&(state->savedPort));
-
- // Convert origin of current port to global coordinates
- // so that when we switch to the window manager's port, we can
- // set up the coordinate system correctly
- origin.h = 0;
- origin.v = 0;
- LocalToGlobal(&origin);
-
- // switch to the wmgrcport
- GetCWMgrPort((CGrafPtr*)&windowManagerPort);
- SetPort(windowManagerPort);
-
- // remember the colors of the wmgrcport
- GetForeColor(&(state->savedFgColor));
- GetBackColor(&(state->savedBgColor));
-
- // remember old origin of wmgrcport
- state->savedOrigin.h = windowManagerPort->portRect.left;
- state->savedOrigin.v = windowManagerPort->portRect.top;
-
- // synchronize wmgrcport's coordinate system with that of the saved port
- SetOrigin(-origin.h, -origin.v);
-
- // remember clip of window manager port and set clip to visRgn of savePort
- state->savedClip = NewRgn();
- GetClip(state->savedClip);
- SetClip(state->savedPort->visRgn);
-
- GetPenState(&(state->savedPen));
- state->savedTxMode = windowManagerPort->txMode;
-
- state->savedPenVis = windowManagerPort->pnVis;
- // maintain pnVis from savePort
- windowManagerPort->pnVis = state->savedPort->pnVis;
- }
-
-
-
- // --------------------------------------------------------------------
- // RestoreSavedPort
- // --------------------------------------------------------------------
- //
- // Restore the drawing context.
- //
-
- void RestoreSavedPort(PortState* state)
- {
- SetOrigin(state->savedOrigin.h, state->savedOrigin.v);
- SetClip(state->savedClip);
- DisposeRgn(state->savedClip);
- SetPenState(&(state->savedPen));
- RGBForeColor(&(state->savedFgColor));
- RGBBackColor(&(state->savedBgColor));
- TextMode(state->savedTxMode);
- SetPort(state->savedPort);
- }
-
-
-
-